## Title: Modified pylas for building LAS QA/QC tools.
## Modified By: Christian Everhart

## Modifications
## May 18, 2010 - Copied necessary functions from the original pylas.py file
## May 06, 2012 - Prepare code for release 0.1 (google code)

import sys, os, struct, getopt, string

##These are the fields as a list of tuples.  
mod_fld_list = [('filesig', 4,'ogr.OFTString')] ##,
##('filesourceid' , 2,ogr.OFTInteger) ,
##               ('reserved'     , 2,ogr.OFTInteger) ,
##               ('guid1'        , 4,ogr.OFTInteger) ,
##               ('guid2'        , 2,ogr.OFTInteger) ,
##               ('guid3'        , 2,ogr.OFTInteger) ,
##               ('guid4'        , 8,ogr.OFTInteger) ,
##               ('vermajor'     , 1,ogr.OFTInteger) ,
##               ('verminor'     , 1,ogr.OFTInteger) ,
##               ('sysid'        , 32,ogr.OFTString) ,
##               ('gensoftware'  , 32,ogr.OFTString) ,
##               ('fileday'      , 2,ogr.OFTInteger) ,
##               ('fileyear'     , 2,ogr.OFTInteger) ,
##               ('headersize'   , 2,ogr.OFTInteger) ,
##               ('offset'       , 4,ogr.OFTInteger) ,
##               ('numvlrecords' , 4,ogr.OFTInteger) ,
##               ('pointformat'  , 1,ogr.OFTInteger) ,
##               ('pointreclen'  , 2,ogr.OFTInteger) ,
##               ('numptrecords' , 4,ogr.OFTInteger) ,
##               ('numptbyresturn', 20,ogr.OFTInteger) ,
##               ('xscale'       , 8,ogr.OFTReal) ,
##               ('yscale'       , 8,ogr.OFTReal) ,
##               ('zscale'       , 8,ogr.OFTReal) ,
##               ('xoffset'      , 8,ogr.OFTReal) ,
##               ('yoffset'      , 8,ogr.OFTReal) ,
##               ('zoffset'      , 8,ogr.OFTReal) ,
##               ('xmax'         , 8,ogr.OFTReal) ,
##               ('xmin'         , 8,ogr.OFTReal) ,
##               ('ymax'         , 8,ogr.OFTReal) ,
##               ('ymin'         , 8,ogr.OFTReal) ,
##               ('zmax'         , 8,ogr.OFTReal) ,
##               ('zmin'         , 8,ogr.OFTReal) ]

#  Copied from the pylas.py module (MIT License: http://pylas.googlecode.com/svn/trunk/pylas.py)
#  LAS header binary structure:
#  (Description, bytes, struct type, array size)
headerstruct = ( ('filesig', 4,'c',4) ,
               ('filesourceid' , 2,'H',1) ,
               ('reserved'     , 2,'H',1) ,
               ('guid1'        , 4,'L',1) ,
               ('guid2'        , 2,'H',1) ,
               ('guid3'        , 2,'H',1) ,
               ('guid4'        , 8,'B',8) ,
               ('vermajor'     , 1,'B',1) ,
               ('verminor'     , 1,'B',1) ,
               ('sysid'        , 32,'c',32) ,
               ('gensoftware'  , 32,'c',32) ,
               ('fileday'      , 2,'H',1) ,
               ('fileyear'     , 2,'H',1) ,
               ('headersize'   , 2,'H',1) ,
               ('offset'       , 4,'L',1) ,
               ('numvlrecords' , 4,'L',1) ,
               ('pointformat'  , 1,'B',1) ,
               ('pointreclen'  , 2,'H',1) ,
               ('numptrecords' , 4,'L',1) ,
               ('numptbyreturn', 20,'L',5) ,
               ('xscale'       , 8,'d',1) ,
               ('yscale'       , 8,'d',1) ,
               ('zscale'       , 8,'d',1) ,
               ('xoffset'      , 8,'d',1) ,
               ('yoffset'      , 8,'d',1) ,
               ('zoffset'      , 8,'d',1) ,
               ('xmax'         , 8,'d',1) ,
               ('xmin'         , 8,'d',1) ,
               ('ymax'         , 8,'d',1) ,
               ('ymin'         , 8,'d',1) ,
               ('zmax'         , 8,'d',1) ,
               ('zmin'         , 8,'d',1) )

#  Copied from the pylas.py module (MIT License: http://pylas.googlecode.com/svn/trunk/pylas.py)
#  LAS Point Data Record Format 0:  (20 bytes)
point_fmt0struct = ( ('x', 4,'L',1) ,
                   ('y', 4,'L',1) ,
                   ('z', 4,'L',1) ,
                   ('intensity', 2,'H',1) ,
                   ('return_grp', 1,'B',1) ,
                   ('classification', 1,'B',1) ,
                   ('scan_angle_rank', 1,'B',1) ,
                   ('extra_1', 1,'B',1) ,  # definition but not size changes between LAS 1.0 and LAS 1.1
                   ('extra_2', 2,'H',1)   # definition but not size changes between LAS 1.0 and LAS 1.1
)

#  Copied from the pylas.py module (MIT License: http://pylas.googlecode.com/svn/trunk/pylas.py)
#  LAS Point Data Record Format 1:   (28 bytes)
point_fmt1struct = ( ('x', 4,'L',1) ,
                   ('y', 4,'L',1) ,
                   ('z', 4,'L',1) ,
                   ('intensity', 2,'H',1) ,
                   ('return_grp', 1,'B',1) ,
                   ('classification', 1,'B',1) ,
                   ('scan_angle_rank', 1,'B',1) ,
                   ('extra_1', 1,'B',1) ,  # definition but not size changes between LAS 1.0 and LAS 1.1
                   ('extra_2', 2,'H',1) ,  # definition but not size changes between LAS 1.0 and LAS 1.1
                   ('gps_time', 8, 'd', 1) 
)

#  Copied from the pylas.py module (MIT License: http://pylas.googlecode.com/svn/trunk/pylas.py)
#    TODO: Document this function is from the 
def parseHeader(filename,verbose=False):
    fh = open(filename,'rb')

    header = {'infile':filename}

    for i in headerstruct:
        try:
            if i[2] == 'c':
                # If it's a string, keep it
                value = fh.read(i[1])
            elif i[3] > 1:
                # If it's an array, unpack to a tuple
                value = struct.unpack( str(i[3]) + i[2] , fh.read(i[1]) ) 
            else:
                # If it's a single binary number
                # Grab the first and only value in the tuple
                value = struct.unpack( i[2] , fh.read(i[1]) )[0]
        except:
            value = fh.read(i[1])

        if verbose:
            print i[0] + '\t', value

        header[i[0]] = value

    fh.close()
    return header

## This is an original function to get a list of LAS files in a directory
def getLASList(inDIR):
    laslist = []
    for f in os.listdir(inDIR):
        if f[-4:].upper() == ".LAS":
            laslist.append(f)
    return laslist

## This will be a statistics class for a header attribute
class StatClass:
    ''' TODO: The accessor/setter methods are not working.  The class data will be manipulated
    directly for now.  Getter methods for calculating stats seem to be working.
    '''
    ##datalist = []
    ##datalist_id = "datalist"

    def __init__(self, did):
        self.datalist = []
        self.datalist_id = did
        
    def datalist_clear(self):
        del self.datalist[:]

    def datalist_len(self):
        return len(self.datalist)

    def datalist_add(self,data):
        datalist.append(data)

    def datalist_replace(self,data,ind):
        if len(datalist) < ind:
            datalist[ind] = data
        
    def datalist_ave(self):
        tot = 0
        for x in self.datalist:
            tot = tot + x
        return tot/len(self.datalist)

    def datalist_minmax(self):
        mindata = self.datalist[0]
        maxdata = self.datalist[0]

        for d in self.datalist:
            if d > maxdata:
                maxdata = d
            if d < mindata:
                mindata = d

        return [mindata,maxdata]

    def datalist_variance(self):
        ave = self.datalist_ave()
        v_tot = 0
        for d in self.datalist:
            v_tot = v_tot + ((d - ave)**2)
        v_ave = v_tot/len(self.datalist)
        return v_ave**0.5

##print "mod_pylas Completed"
